package cn.demoncat.util.sec;

import cn.demoncat.util.exception.ParamRuntimeException;
import cn.demoncat.util.lang.StringUtil;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES/CBC/PKCS5Padding + BASE64 对称加密
 *
 * @author 延晓磊
 * @since 2020年12月10日
 */
public class AesCbcPkcs5PaddingUtil {

    /**
     * 加密
     *
     * @param src   源文
     * @param key   密钥，限16 bytes
     * @param iv    偏移量，限16 bytes
     * @return
     *
     * @author 延晓磊
     * @since 2020年12月10日
     */
    public static String encrypt(String src, String key, String iv) {
        // 密钥
        byte[] keys = StringUtil.getBytes(key);
        SecretKeySpec sk = new SecretKeySpec(keys, "AES");
        // 偏移量，增加加密算法的强度
        IvParameterSpec ivs = new IvParameterSpec(StringUtil.getBytes(iv));
        try {
            // 算法/模式/补码方式
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, sk, ivs);
            // AES加密
            byte[] aes = cipher.doFinal(StringUtil.getBytes(src));
            // BASE64加密
            return Base64Util.encode(aes);
        }catch (Exception e){
            throw new ParamRuntimeException("AES/CBC加密失败", e);
        }
    }

    /**
     * 解密
     *
     * @param src   密文
     * @param key   密钥，限16 bytes
     * @param iv    偏移量，限16 bytes
     *
     * @return 源文
     *
     * @author 延晓磊
     * @since 2020年12月10日
     */
    public static String decrypt(String src, String key, String iv) {
        // 密钥
        byte[] keys = StringUtil.getBytes(key);
        SecretKeySpec sk = new SecretKeySpec(keys, "AES");
        // 偏移量，增加加密算法的强度
        IvParameterSpec ivs = new IvParameterSpec(StringUtil.getBytes(iv));
        try {
            // 算法/模式/补码方式
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, sk, ivs);
            // BASE64解密
            byte[] base64 =  Base64Util.decode(src);
            // AES解密
            return StringUtil.getStr(cipher.doFinal(base64));
        }catch (Exception e){
            throw new ParamRuntimeException("AES/CBC解密失败", e);
        }
    }


}
